////////////////////////////////////////////////
// DESCRIPTION:
//    Standardized Bit manipulation inline functions
//
// Legal Notices:
//     Copyright (c) 2008, Telliam Consulting, LLC.
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification,
//     are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright notice,
//       this list of conditions and the following disclaimer in the documentation
//       and/or other materials provided with the distribution.
//
//     * Neither the name of Telliam Consulting nor the names of its contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// Disclaimer:
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//     IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
//     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//     LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
//     OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
//     OF THE POSSIBILITY OF SUCH DAMAGE.  
//
#pragma once

// Group = BitFlags

// these are macros to allow use of this header from legacy "C" code.

#define BIT_0  (0x00000001)  
#define BIT_1  (0x00000002)  
#define BIT_2  (0x00000004)  
#define BIT_3  (0x00000008)  
#define BIT_4  (0x00000010)  
#define BIT_5  (0x00000020)  
#define BIT_6  (0x00000040)  
#define BIT_7  (0x00000080)  
#define BIT_8  (0x00000100)  
#define BIT_9  (0x00000200)  
#define BIT_10 (0x00000400)  
#define BIT_11 (0x00000800)  
#define BIT_12 (0x00001000)  
#define BIT_13 (0x00002000)  
#define BIT_14 (0x00004000)  
#define BIT_15 (0x00008000)  
#define BIT_16 (0x00010000)  
#define BIT_17 (0x00020000)  
#define BIT_18 (0x00040000)  
#define BIT_19 (0x00080000)  
#define BIT_20 (0x00100000)  
#define BIT_21 (0x00200000)  
#define BIT_22 (0x00400000)  
#define BIT_23 (0x00800000)  
#define BIT_24 (0x01000000)  
#define BIT_25 (0x02000000)  
#define BIT_26 (0x04000000)  
#define BIT_27 (0x08000000)  
#define BIT_28 (0x10000000)  
#define BIT_29 (0x20000000)  
#define BIT_30 (0x40000000)  
#define BIT_31 (0x80000000)  

#if defined(__cplusplus)
namespace FusionWare
{
    ///////////////////////////////////////////////////////////
    // Description:
    //    General Bit flag manipulation functions
    // 
    // Remarks:
    //    
    namespace BitFlags
    {
        ///////////////////////////////////////////////////////
        // Description: 
        //    Clears a bit flag
        //
        // Input: 
        //    Source Initial value to clear the bit(s) from
        //    Flags  Flags indicating which bit(s) to clear 
        //
        // Returns: 
        //     Modified value
        //     
        __forceinline UINT32 ClearFlags(UINT32 Source, UINT32 Flags)
        {
            return Source & ~Flags;
        }

        ////////////////////////////////////////////////
        // Description:
        //    Masks a value with a set of flags
        // 
        // Input:
        //    Source Source value
        //    Mask   Mask value to use to AND with the Value
        // 
        // Return:
        //    Masked version of the Source
        // 
        __forceinline UINT32 MaskFlags(UINT32 Source, UINT32 Mask)
        {
            return Source & Mask;
        }


        ////////////////////////////////////////////////
        // Description:
        //    Determines if all flags are set
        //
        // Input:
        //    Source - value conatining flags to be tested
        //    Flag   - flags to test if set in Source
        //
        // Returns:
        //    true  - All of the flags are set
        //    false - Not all flags are set
        //
        __forceinline bool AllFlagsSet(UINT32 Source, UINT32 Flags)
        {
            return (Source & Flags) == Flags;
        }

        ////////////////////////////////////////////////
        // Description:
        //    Determines if any flag is set
        //
        // Input:
        //    Source - value conatining flags to be tested
        //    Flag   - flags to test if set in Source
        //
        // Returns:
        //    true  - One or more of the flags is set
        //    false - None of the flags are set
        //
        __forceinline bool IsFlagSet(UINT32 Source, UINT32 Flag)
        {
            return (Source & Flag) != 0;
        }

        ////////////////////////////////////////////////
        // Description:
        //    Sets flags in a value
        // 
        // Input:
        //    Source Initial value
        //    Flags  Flags to set in the Source Value
        //
        // Returns:
        //    Modified value
        //
        __forceinline UINT32 SetFlags(UINT32 Source, UINT32 Flags)
        {
            return Source | Flags;
        }


        ///////////////////////////////////////////////////////
        // Description: 
        //    Modifys bits in a UINT32 value
        //
        // Input: 
        //    Source    - Original bits to change
        //    ClearBits - Bits to clear in Source
        //    SetBits   - Bits to set in source
        //
        // Returns: 
        //    UINT32 newly modified version of source bits
        //     
        __forceinline UINT32 ModifyFlags(UINT32 Source, UINT32 ClearBits, UINT32 SetBits)
        {
            return (Source & ~ClearBits) | SetBits;
        }

        ///////////////////////////////////////////////////////
        // Description: 
        //    Performs an Atomic modification of bit flags
        //
        // Input: 
        //    pAddress  - Address of the flag variable/register
        //    ClearBits - Bits to clear
        //    SetBits   - Bits to set
        //
        // Returns: 
        //     Original value of the flags/register before modification
        //     
        // Remarks: 
        //     Used to perform thread and interrupt safe Read-Modify-Write
        //     bit set and clear functions. 
        //
        inline UINT32 InterlockedModifyFlags(volatile UINT32* pValue, UINT32 ClearBits, UINT32 SetBits)
        {
            UINT32 original, newVal;
            do {
                 original = *pValue;
                 newVal = ModifyFlags(original, ClearBits, SetBits);
                 // if the correct bits are already set/cleared then do nothing
                 if(newVal == original)
                    break;
             // use InterloackedCopmaresExchange to make an int safe assignment or try again
            }while(InterlockedCompareExchange((long*)pValue, newVal, original) != original);
            return original;
        }

        __forceinline UINT32 InterlockedModifyFlags(volatile UINT32& Value, UINT32 ClearBits, UINT32 SetBits)
        {
            return InterlockedModifyFlags(&Value, ClearBits, SetBits);
        }
    }
}
#endif //__cplusplus
